/*
 * Copyright [2020-2030] [https://www.stylefeng.cn]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Guns采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Guns源码头部的版权声明。
 * 3.请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://gitee.com/stylefeng/guns
 * 5.在修改包名，模块名称，项目代码等时，请注明软件出处 https://gitee.com/stylefeng/guns
 * 6.若您的项目无法满足以上几点，可申请商业授权
 */
package cn.stylefeng.guns.modular.business.service.impl;

import static cn.stylefeng.roses.kernel.file.api.constants.FileConstants.DEFAULT_BUCKET_NAME;
import static cn.stylefeng.roses.kernel.file.api.constants.FileConstants.FILE_POSTFIX_SEPARATOR;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import cn.stylefeng.guns.modular.business.utils.ZIPUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.guns.core.exception.BusinessException;
import cn.stylefeng.guns.modular.business.entity.Sample;
import cn.stylefeng.guns.modular.business.entity.SampleType;
import cn.stylefeng.guns.modular.business.exception.MyBusinessExceptionEnum;
import cn.stylefeng.guns.modular.business.facotry.SampleFactory;
import cn.stylefeng.guns.modular.business.mapper.SampleMapper;
import cn.stylefeng.guns.modular.business.service.SampleService;
import cn.stylefeng.guns.modular.business.utils.ScctcConst;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
import cn.stylefeng.roses.kernel.db.api.factory.PageFactory;
import cn.stylefeng.roses.kernel.db.api.factory.PageResultFactory;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import cn.stylefeng.roses.kernel.file.api.FileOperatorApi;
import cn.stylefeng.roses.kernel.file.api.exception.FileException;
import cn.stylefeng.roses.kernel.file.api.exception.enums.FileExceptionEnum;
import cn.stylefeng.roses.kernel.file.api.util.DownloadUtil;
import lombok.extern.slf4j.Slf4j;

import cn.stylefeng.guns.modular.business.service.TypeService;
/**
 * 文件信息表 服务实现类
 *
 * @author stylefeng
 * @date 2020/6/7 22:15
 */
@Service
@Slf4j
public class SampleServiceImpl extends ServiceImpl<SampleMapper, Sample> implements SampleService {

//	@Value("${web.upload-path}")
//	public String uploadPath;
	
    @Resource
    private FileOperatorApi fileOperatorApi;

    @Autowired
    private TypeService typeService;

	@Autowired
	private RestTemplate restTemplate;

	@Override
    public Sample getSampleResult(Long fileId) {

        // 查询库中文件信息
   
		Sample sample = new Sample();
		sample = this.getById(fileId);
        return sample;
    }



	@Override
    @Transactional(rollbackFor = Exception.class)
    public Sample uploadFile(MultipartFile file) {

        // 文件请求转换存入数据库的附件信息
		Sample sample =SampleFactory.createSample(file);
     
     

        // 保存附件到附件信息表
        this.save(sample);

      
       
        return sample;
    }

  

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteReally(Sample sample) {

       
        // 批量删除
        this.removeById(sample.getSampleId());

        // 删除具体文件
       
        this.fileOperatorApi.deleteFile(sample.getSampleBucket(), sample.getSampleObjectName());
    }

 
	@Override
    public PageResult<Sample> sampleListPage(Sample sample) {
        Page<Sample> page = PageFactory.defaultPage();
        List<Sample> list = this.baseMapper.SampleList(page,sample);
        return PageResultFactory.createPageResult(page.setRecords(list));
    }
	
	//根据状态查询，只返回状态为0的对象
	@Override
    public PageResult<Sample> sampleListPageByStatus0(Sample sample) {
        Page<Sample> page = PageFactory.defaultPage();
        List<Sample> list = this.baseMapper.SampleList0(page,sample);
        return PageResultFactory.createPageResult(page.setRecords(list));
    }
	
	@Override
    public PageResult<Sample> sampleListPageByStatus1(Sample sample) {
        Page<Sample> page = PageFactory.defaultPage();
        List<Sample> list = this.baseMapper.SampleList1(page,sample);
        return PageResultFactory.createPageResult(page.setRecords(list));
    }
	

	@Override
    public void packagingDownload(String sampleIds, HttpServletResponse response) {

        // 获取文件信息
        List<Long> sampleIdList = Arrays.stream(sampleIds.split(",")).map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
        List<Sample> sampleList = this.baseMapper.getSampleListByFileIds(sampleIdList);

        // 输出流等信息
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(bos);

        try {
            for (int i = 0; i < sampleList.size(); i++) {
                Sample sample = sampleList.get(i);
                if (ObjectUtil.isNotEmpty(sample)) {
                    String fileOriginName = sample.getSampleOriginName();
                   

                    byte[] fileBytes = fileOperatorApi.getFileBytes(DEFAULT_BUCKET_NAME, sample.getSampleObjectName());
                    ZipEntry entry = new ZipEntry(i + 1 + "." + fileOriginName);
                    entry.setSize(fileBytes.length);
                    zip.putNextEntry(entry);
                    zip.write(fileBytes);
                }
            }
            zip.finish();

            // 下载文件
            DownloadUtil.download(DateUtil.now() + "-打包下载" + FILE_POSTFIX_SEPARATOR + "zip", bos.toByteArray(), response);
        } catch (Exception e) {
            log.error("获取文件流异常，具体信息为：{}", e.getMessage());
            throw new FileException(FileExceptionEnum.FILE_STREAM_ERROR);
        } finally {
            try {
                zip.closeEntry();
                zip.close();
                bos.close();
            } catch (IOException e) {
                log.error("关闭数据流失败，具体信息为：{}", e.getMessage());
            }
        }
    }


	@Override
    public List<Sample> getSampleListByFileIds(String fileIds) {
        List<Long> fileIdList = Arrays.stream(fileIds.split(",")).map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
        return this.baseMapper.getSampleListByFileIds(fileIdList);
    }

    
    

    

   

	@Override
    public Sample detail(long sampleId) {
        return this.getSampleResult(sampleId);
    }

	@Override
    @Transactional(rollbackFor = Exception.class)
    public Sample update(MultipartFile file,Sample sample) {
		
		
		Sample sampleSave = new Sample();
		 
		sampleSave = getSampleResult(sample.getSampleId());
		
	        LoginUser loginUser = LoginContext.me().getLoginUser();
	        
	        //sampleSave.setSampleBucket(DEFAULT_BUCKET_NAME);
	       
	        sampleSave.setSampleStatus("0");//0：未分析
	        sampleSave.setUpdateUser(loginUser.getUserId());
	        
	        sampleSave.setUpdateUserName(loginUser.getAccount());
	        sampleSave.setTypeName(sample.getTypeName());
	        sampleSave.setSampleType(sample.getSampleType());
	        sampleSave.setSampleZhName(sample.getSampleZhName());
	        sampleSave.setSampleEnName(sample.getSampleEnName());
	        sampleSave.setSampleIntroduction(sample.getSampleIntroduction());
	        // 保存附件到附件信息表
            this.saveOrUpdate(sampleSave);

      
        // 返回结果
        return sampleSave;
    }



	/**
	 *解析Sample
	 */
	@Override
	public Sample analysisSample(Sample sample) throws IOException {
		sample = this.getById(sample.getSampleId());
		File file = new File(sample.getSamplePath());
		
		if (!file.exists()) {
			throw new BusinessException(MyBusinessExceptionEnum.SELECT_ERROR);
		}
		
		String path = "temp_dir" + System.currentTimeMillis();
		File tempDir = new File(path);
		try {
			if (!tempDir.exists()) {
				System.out.println("mkdir:" + tempDir.mkdirs());
			}
		
//				请求地址
				String url = ScctcConst.CUCKOO_URL + "/tasks/create/file";
//        POST
				MultiValueMap<String, Object> bodyMap = new LinkedMultiValueMap<>();
				bodyMap.add("file", new FileSystemResource(file));
				HttpHeaders headers = new HttpHeaders();
				headers.setContentType(MediaType.MULTIPART_FORM_DATA);
				HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(bodyMap, headers);
				ResponseEntity<JSONObject> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, JSONObject.class);
				sample.setTaskId(response.getBody().getLongValue("task_id"));
				sample.setSampleStatus("1");
				sample.setUpdateTime(DateTimeToDate());
				// 保存附件到附件信息表
				this.saveOrUpdate(sample);
			

		}catch (Exception e){
			throw  e;
		}finally {
			ZIPUtils.deleteFile(tempDir);
		}
		return sample;
	}
	

	/**
	 *创建Sample
	 * @throws Exception 
	 */
	@Override
	public Sample addSampleAndFile(MultipartFile file, Sample sample) throws Exception {
		if (file.isEmpty()) {
			throw new BusinessException(MyBusinessExceptionEnum.SELECT_ERROR);
		}
		File fileTemp = convert(file);
		String path = "temp_dir" + System.currentTimeMillis();
		File tempDir = new File(path);
		try {
			if (!tempDir.exists()) {
				System.out.println("mkdir:" + tempDir.mkdirs());
			}
			ZIPUtils.unZipFiles(fileTemp, path);

			File[] files = tempDir.listFiles();
			for (File f : files) {
				// 文件请求转换存入数据库的附件信息
				Sample saveSample = SampleFactory.createSampleByFile(f, sample);
				saveSample.setSampleZhName(f.getName());
				
				
				saveSample.setCreateTime(DateTimeToDate());
				// 保存附件到附件信息表
				this.save(saveSample);
			}

		}catch (Exception e){
			throw  e;
		}finally {
			ZIPUtils.deleteFile(tempDir);
		}
		return sample;
	}
	/**
	 *上传一个压缩包（包含多个压缩包），批量创建Sample
	 */
	@Override
	public Boolean addSampleByFile(MultipartFile file) throws IOException {
		if (file.isEmpty()) {
			throw new BusinessException(MyBusinessExceptionEnum.SELECT_ERROR);
		}
		File fileTemp = convert(file);
		String path = "temp_dir" + System.currentTimeMillis();
		File tempDir = new File(path);
		try {
			if (!tempDir.exists()) {
				System.out.println("mkdir:" + tempDir.mkdirs());
			}
			ZIPUtils.unZipFiles(fileTemp, path);

			File[] files = tempDir.listFiles();
			for (File f : files) {
				// 文件请求转换存入数据库的附件信息
				Sample saveSample = SampleFactory.createSampleByFile(f,new Sample());
				saveSample.setSampleZhName(f.getName());				
				String name = f.getName();
				//病毒家族
				String sampleType="";
				//病毒类别
				String typeName="";
				if(name.contains(".")) {
					
					String[] list = f.getName().split("\\.");
					
					if(list.length>=2) {
						//病毒家族
						sampleType = list[1];
						//病毒类别
						typeName = list[0];
					}
					
				}
				
				
				SampleType type = new SampleType();
				
				type.setTypeEnglish(typeName);
				SampleType type2 = typeService.selectBytypeName(type);
				if(null==type2 ) {
					if(!"".equals(typeName)) {
						type.setCreateTime(new Date());
						typeService.save(type);
						type2 = typeService.selectBytypeName(type);
					}
					
				}
				if(null!=type2) {
					//病毒类别
					
					saveSample.setTypeName(type2.getTypeName());
					saveSample.setTypeId(type2.getTypeId());
				}
				
				saveSample.setSampleType(sampleType);
				
				saveSample.setCreateTime(DateTimeToDate());
				// 保存附件到附件信息表
				this.save(saveSample);
			}

		}catch (Exception e){
			throw  e;
		}finally {
			ZIPUtils.deleteFile(tempDir);
		}
		return true;
	}
	
	  public static File convert(MultipartFile file)
	  {    
	    File convFile = new File("temp_image", file.getOriginalFilename());
	    if (!convFile.getParentFile().exists()) {
	            System.out.println("mkdir:" + convFile.getParentFile().mkdirs());
	    }
	    try {
	        convFile.createNewFile();
	          FileOutputStream fos = new FileOutputStream(convFile); 
	            fos.write(file.getBytes());
	            fos.close(); 
	    } catch (IOException e) {
	        e.printStackTrace();
	    } 
	    return convFile;
	 }



	@Override
	public String viewReport(long taskID) {
      String url =ScctcConst.CUCKOO_URL+ "/tasks/report/"+taskID;
	   Map<String, String> map = new HashMap<>();
	   try {
		   ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, map);
		   
	       HttpStatus statusCode = responseEntity.getStatusCode();	  
	       if(statusCode == HttpStatus.OK) {
	     	  return responseEntity.getBody();
	       }else {
	     	  return null;
	       }
		} catch (ResourceAccessException e) {
			return null;
		}
	}


	@Override
	public String getTaskStatus(long taskID) {
		
	   try {
		   String url =ScctcConst.CUCKOO_URL+ "/tasks/report/"+taskID;
	       Map<String, String> map = new HashMap<>();
	       ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, map);
	       System.out.println(responseEntity.getBody());
	       HttpStatus statusCode = responseEntity.getStatusCode();
	       System.out.println(responseEntity.getBody());
	       if(statusCode == HttpStatus.OK) {
	     	  return responseEntity.getBody();
	       }else {
	     	  return null;
	       }
		} catch (ResourceAccessException e) {
			return null;
		}
     
	}

	@Override
	public void downloadReport(long taskID, HttpServletResponse response) {
		String url = ScctcConst.CUCKOO_URL+"/tasks/report/"+taskID+"/all";
       Map<String, String> map = new HashMap<>();
       ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, map);
     
//       DownloadUtil.download(sysFileInfoResponse.getFileOriginName(), sysFileInfoResponse.getFileBytes(), response);
	}



	@Override
	public String testCuckoo() {
      try {
    	  String url = ScctcConst.CUCKOO_URL+"/cuckoo/status";
          Map<String, String> map = new HashMap<>();
          ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, map);
          HttpStatus statusCode = responseEntity.getStatusCode();
         
          if(statusCode == HttpStatus.OK) {
        	  return null;
          }else {
        	  return "Cuckoo api 服务不可用，修复后重试。";
          }
        	
		} catch (ResourceAccessException e) {
			return "Cuckoo api 服务不可用，修复后重试。";
		}
	}
	

	/**
	 * 样本类型百分比
	 * @return
	 */
	public JSONArray staticTypePer(){
		List<Sample> sampleList = this.baseMapper.staticTypePer();
		JSONArray arr = new JSONArray();
		//[{value: 1048, name: '木马'},{value: 735, name: '病毒'}]
		for(int i = 0;i < sampleList.size();i++){
			Sample sample = sampleList.get(i);
			JSONObject obj = new JSONObject();
			obj.put("value", sample.getSampleId());
			obj.put("name", sample.getTypeName());
			arr.add(obj);
		}
		
		return arr;
	}
	/**
	 * 样本类型排行
	 * @return
	 */
	public JSONObject staticTypeTop(){
		List<Sample> sampleList = this.baseMapper.staticTypeTop();
		Integer[] yData = new Integer[sampleList.size()];
		String[] xData = new String[sampleList.size()];
		// yData [50, 100, 150]
		// xData ["xml", "txt", "xls"]
		for(int i = 0;i < sampleList.size();i++){
			Sample sample = sampleList.get(i);
			yData[i] = sample.getSampleId().intValue();
			xData[i] = sample.getTypeName();
		}
		JSONObject obj = new JSONObject();
		obj.put("xData", xData);
		obj.put("yData", yData);
		return obj;
	}
	/**
	 * 样本添加趋势
	 * @return
	 */
	public JSONObject staticFileCount(){
		
		List<Sample> sampleList = this.baseMapper.staticFileCount();
		Integer[] yData = new Integer[sampleList.size()];
		String[] xData = new String[sampleList.size()];
		// yData [50, 100, 150]
		// xData ["2021-02-01", "2021-02-02", "2021-02-03"]
		for(int i = 0;i < sampleList.size();i++){
			Sample sample = sampleList.get(i);
			yData[i] = sample.getSampleId().intValue();
			Date dd = sample.getCreateTime();
			if(StringUtils.isEmpty(dd)){
				xData[i] = "NaN";
			}else{
				 xData[i] = DateUtil.format(sample.getCreateTime(), "yy年MM月dd日"); 
				 
			}
		}
		JSONObject obj = new JSONObject();
		obj.put("xData", xData);
		obj.put("yData", yData);
		return obj;
	}
	
	public Date DateTimeToDate(){
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String s = sdf.format(new Date());
		Date date = null;
		try {
			date = sdf.parse(s);
		} catch (ParseException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		return date;
	}

   



}
